package com.ruoyi.web.controller.gatewayManagement;

import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.service.IAirDetailsService;
import com.ruoyi.system.service.IMqttConfigService;
import com.ruoyi.system.service.IReservationTaskService;
import com.ruoyi.web.controller.mqtt.MqttPushClient;
import io.minio.MinioClient;
import io.minio.PutObjectOptions;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;

/**
 * airDetailsController
 * 
 * @author LGD
 * @date 2025-07-18
 */
@RestController
@RequestMapping("/gatewayManagement/airDetails")
//@EnableScheduling     //开始定时任务
public class AirDetailsController extends BaseController
{
    @Autowired
    private IAirDetailsService airDetailsService;

    @Autowired
    private IMqttConfigService mqttConfigService;

    @Autowired
    private MinioConfig minioConfig;

    @Resource
    private MinioClient minioClient;

    @Autowired
    private IReservationTaskService reservationTaskService;

    /**
     * 查询airDetails列表
     */
    @PreAuthorize("@ss.hasPermi('gatewayManagement:airDetails:list')")
    @GetMapping("/list")
    public TableDataInfo list(AirDetails airDetails)
    {
        startPage();
        List<AirDetails> list = airDetailsService.selectAirDetailsList(airDetails);
        return getDataTable(list);
    }

    /**
     * 导出airDetails列表
     */
    @PreAuthorize("@ss.hasPermi('gatewayManagement:airDetails:export')")
    @Log(title = "airDetails", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, AirDetails airDetails)
    {
        List<AirDetails> list = airDetailsService.selectAirDetailsList(airDetails);
        ExcelUtil<AirDetails> util = new ExcelUtil<AirDetails>(AirDetails.class);
        util.exportExcel(response, list, "airDetails数据");
    }

    /**
     * 获取airDetails详细信息
     */
    @PreAuthorize("@ss.hasPermi('gatewayManagement:airDetails:query')")
    @GetMapping(value = "/{airDetailsId}")
    public AjaxResult getInfo(@PathVariable("airDetailsId") Long airDetailsId)
    {
        return success(airDetailsService.selectAirDetailsByAirDetailsId(airDetailsId));
    }

    /**
     * 新增airDetails
     */
    @PreAuthorize("@ss.hasPermi('gatewayManagement:airDetails:add')")
    @Log(title = "airDetails", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody AirDetails airDetails)
    {
        return toAjax(airDetailsService.insertAirDetails(airDetails));
    }

    /**
     * 修改airDetails
     */
    @PreAuthorize("@ss.hasPermi('gatewayManagement:airDetails:edit')")
    @Log(title = "airDetails", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody AirDetails airDetails)
    {
        return toAjax(airDetailsService.updateAirDetails(airDetails));
    }

    /**
     * 删除airDetails
     */
    @PreAuthorize("@ss.hasPermi('gatewayManagement:airDetails:remove')")
    @Log(title = "airDetails", businessType = BusinessType.DELETE)
	@DeleteMapping("/{airDetailsIds}")
    public AjaxResult remove(@PathVariable Long[] airDetailsIds)
    {
        return toAjax(airDetailsService.deleteAirDetailsByAirDetailsIds(airDetailsIds));
    }

    //    找到应用服务区配置信息
    @Anonymous
    @GetMapping("/mqttConfigInfo")
    public AjaxResult mqttConfigInfo(){
        List<MqttConfig> mqttConfigList = mqttConfigService.selectMqttConfigList(new MqttConfig());
        if (mqttConfigList == null){
            return AjaxResult.error("服务器配置信息为空");
        }
        return AjaxResult.success(mqttConfigList);
    }

    // 设备上电
    public void addDevice(@RequestBody AirDetails airDetails){
        AirDetails air = new AirDetails();
        air.setMainboardId(airDetails.getMainboardId());
        List<AirDetails> airDetailsList = airDetailsService.selectAirDetailsList(air);
        if (airDetailsList.size() > 0){
            airDetails.setAirDetailsId(airDetailsList.get(0).getAirDetailsId());
            toAjax(airDetailsService.updateAirDetails(airDetails));
            return;
        }
        airDetails.setStatus("未配置");
        toAjax(airDetailsService.insertAirDetails(airDetails));
    }

    /**
     *  更新 状态
     *
    */
    public void updateAirStatus( AirDetails airDetails ){
        AirDetails air = new AirDetails();
        air.setMainboardId(airDetails.getMainboardId());
        //  找出匹配的 ID
        List<AirDetails> airDetailsList = airDetailsService.selectAirDetailsList(air);
        if (airDetailsList.isEmpty()){
            return;
        }
        airDetails.setAirDetailsId(airDetailsList.get(0).getAirDetailsId());
        toAjax(airDetailsService.updateAirDetails(airDetails));
    }

    //  发布应用服务信息 （ 多条 ）
    @Anonymous
    @PostMapping("/migrationService")
    public AjaxResult migrationService(@RequestBody Long[] mainboardIds) {
        System.out.println("----前端数据-主板ID--"+  Arrays.toString(mainboardIds));
        //  主板ID 列表
        List<String> mainboardIdList = Arrays.stream(mainboardIds)
                .map(Object::toString)
                .collect(Collectors.toList());
        List<MqttConfig> mqttConfigList = mqttConfigService.selectMqttConfigList(new MqttConfig());
        if (mqttConfigList == null) {
            return AjaxResult.error("未找到服务器配置信息！");
        }
        //  发送消息
        JSONObject jsonObject = new JSONObject();
        mainboardIdList.forEach(id -> {
            jsonObject.put("msg_type", 1);
            jsonObject.put("mqtt_ip", mqttConfigList.get(0).getMqttIp());
            jsonObject.put("mqtt_port", mqttConfigList.get(0).getMqttPort());
            jsonObject.put("user_name", mqttConfigList.get(0).getMqttName());
            jsonObject.put("pw", mqttConfigList.get(0).getMqttPw());
            jsonObject.put("msg_id", mqttConfigList.get(0).getMsgId());
            System.out.println("---发送数据---"+ String.valueOf(jsonObject) );
            //  发布订阅
            MqttPushClient.publishMessage(id, String.valueOf(jsonObject),0);
        });
        return AjaxResult.success("发布配置订阅成功");
    }

    //  后端远程 OTA
    @Anonymous
    @PostMapping("/remoteOTA")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult remoteOTA(@RequestBody OTADto otaDto ){
        System.out.println(otaDto.getSelectType()+"----前端数据-主板ID--"+  otaDto  );
        ReservationTask task = new ReservationTask();
        task.setReservationTime(DateUtils.getTime());
        task.setMatter("更新文件");
        task.setDownloadPath(otaDto.getDownloadUrl());
        task.setReservationStatus("1");
        int i = reservationTaskService.insertReservationTask(task);
        if (i != 1){
            return AjaxResult.error("文件上传失败，请重试！");
        }
        List<AirDetails> mainboardIdList = new ArrayList<>();
        if (otaDto.getSelectType().equals("1")){     //  全量更新
            mainboardIdList = airDetailsService.selectAirDetailsList(new AirDetails());
            if (mainboardIdList == null) {
                return AjaxResult.error("设备列表为空");
            }
        }else {
            Arrays.stream(otaDto.getMainboardIds())
                    .map(Object::toString)
                    .map(AirDetails::new)
                    .forEach(mainboardIdList::add);
            System.out.println("----shujupinjie----"+ mainboardIdList);
        }


        // 优化
        Timer timer=new Timer();
        List<AirDetails> finalMainboardIdList = null;
        if (otaDto.getSelectType().equals("1")){
            finalMainboardIdList = mainboardIdList.stream()
                .filter(item -> "0".equals(item.getPowerOnStatus()))
                .collect(Collectors.toList());
        }else {
            finalMainboardIdList = mainboardIdList;
        }

        System.out.println("-----筛选出数据-----"+ finalMainboardIdList);

        List<AirDetails> finalMainboardIdList1 = finalMainboardIdList;
        timer.schedule(new TimerTask(){
            public void run(){
            UpdateOTA(finalMainboardIdList1);
            this.cancel();
        }},500);
        return AjaxResult.success("开始后端发布订阅");
    }

    //  升级 OTA
    public void UpdateOTA(List<AirDetails> mainboardIdList ){
        System.out.println("--------升级---------"+ mainboardIdList);
        final int BATCH_SIZE = 1;     //  更新条数
        final long SLEEP_TIME = 10 * 1000;   // 休眠时间

        // 分批处理逻辑
        IntStream.range(0, (mainboardIdList.size() + BATCH_SIZE - 1) / BATCH_SIZE)
            .mapToObj(i -> mainboardIdList.subList(
                    i * BATCH_SIZE,
                    Math.min((i + 1) * BATCH_SIZE, mainboardIdList.size())
            ))
            .forEach(batch -> {
                // 处理当前批次
                batch.forEach(item -> {
                    // 筛选出 不在线设备
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("msg_type", 3);
                    jsonObject.put("url", "http://4df2c630.r7.cpolar.top/gatewayManagement/airDetails/downloadFile");
                    jsonObject.put("msg_id", 123);
                    System.out.println("---OTA板子ID ---" + item.getMainboardId());

                        MqttPushClient.publishMessage(
                                item.getMainboardId(),
                                String.valueOf(jsonObject),
                                0
                        );

                    System.out.println( "------发布订阅一次----");
                });
                // 非最后一批时休眠
                if (batch.size() == BATCH_SIZE &&
                        batch.get(BATCH_SIZE - 1) != mainboardIdList.get(mainboardIdList.size() - 1)) {
                    try {
                        Thread.sleep(SLEEP_TIME);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        System.err.println("线程休眠被中断，终止后续处理");
                    }
                }
            });
    }

    //  查询网关配置信息
    @PostMapping("/selectGatewayConfigInfo")
    public AjaxResult selectGatewayConfigInfo(@RequestBody Long[] mainboardIds){
        System.out.println(Arrays.toString(mainboardIds)+"**********");
        return null;
    }

    //  上传 文件
    @Anonymous
    @PostMapping("/uploadAirFile")
    public AjaxResult uploadAirFile(MultipartFile file){
        String uuid = UUID.randomUUID().toString().replace("-", "");
        System.out.println("-----文件名----"+ file.getOriginalFilename() );
        String filename = uuid + file.getOriginalFilename();
        String url = null;
        try {
            InputStream in = file.getInputStream();
            MinioClient minioClient = minioConfig.minioClient();
            minioClient.putObject(minioConfig.getBucketName(),filename, in , new PutObjectOptions(in.available(), -1));
            in.close();
            url = minioConfig.getEndpoint()+"/"+ minioConfig.getBucketName()+"/"+ filename;
            System.out.println("------uuuuuuuuurl----" + filename);
        }catch (Exception e){
            System.out.println(e.toString());
            return AjaxResult.error("上传错误："+ e.toString());
        }
        return AjaxResult.success(filename);
    }

    /**
     * 下载文件
     *
//     * @param fileName 文件名
     * @param response HttpServletResponse
     */
    @Anonymous
    @GetMapping("/downloadFile")
    @Transactional(rollbackFor = Exception.class)   //  回滚
    public void downloadFile(HttpServletResponse response) {
        List<ReservationTask> taskList = reservationTaskService.selectReservationTaskList(new ReservationTask());
        //  获取 最新 文件名
        String fileName = taskList.get(0).getDownloadPath();
        // 获取桶名
        String bucketName = minioConfig.getBucketName();
        if (StringUtils.isBlank(fileName)) {
            System.out.println("----文件空----");
            return;
        }
        try {
            // 获取文件流
            InputStream file = minioClient.getObject(bucketName,fileName);
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(fileName.substring(fileName.lastIndexOf("/") + 1), StandardCharsets.UTF_8));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            // 获取输出流
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = file.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            file.close();
            servletOutputStream.close();
            System.out.println( "---下载成功：---"+fileName);
        } catch (Exception e) {
            System.out.println("文件名: " + fileName + "下载文件时出现异常: " + e);
        }
    }

    // 预约执行任务
    @Anonymous
    @PostMapping("/reserveDownloadTask")
    public AjaxResult reserveDownloadTask(@RequestBody ReservationTask task){
        task.setReservationStatus("0");
        int  i = reservationTaskService.insertReservationTask(task);
        if (i != 1){
            return AjaxResult.error("预约失败，请重试！");
        }
        List<AirDetails> mainboardIdList = airDetailsService.selectAirDetailsList(new AirDetails());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime targetTime = LocalDateTime.parse(task.getReservationTime(), formatter);   // 格式：2025-07-28T17:05:49

        long delay = Duration.between(LocalDateTime.now(), targetTime).getSeconds();
        System.out.println("---延迟时间---"+ delay );
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.schedule(() -> {
            System.out.println("任务延迟执行！");
            UpdateOTA(mainboardIdList);
            scheduler.shutdown();
        }, delay, TimeUnit.SECONDS);

        return AjaxResult.success("操作成功");
    }
}
